//! @file   lc_mutex.cpp
//! @brief  
//! @author Sayan Chaliha
//! @date   September, 2011
//!
//! 
#include <lc_mutex.h>
#include <lc_system.h>

namespace cyan {
    Mutex::Mutex() {
        Int count = 0;
        pthread_mutexattr_t attributes;
        
        pthread_mutexattr_init(&attributes);
        pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE);
        
        Int returnCode = ::pthread_mutex_init(&this->mutex_, &attributes);
        
        while ((returnCode != 0) && (returnCode == EAGAIN ||
                                     returnCode == EBUSY)) {
            returnCode = ::pthread_mutex_init(&this->mutex_, &attributes);
            if (returnCode == 0 || ++count == MAX_RETRIES)
                break;
            System::sleep(1);
        }
        
        if (returnCode == 0)
            return;
        
        System::throwSystemException(returnCode);
    }
    
    Mutex::~Mutex() {
        Int count = 0;
        Int returnCode = ::pthread_mutex_destroy(&this->mutex_);
        
        while ((returnCode != 0) && (returnCode == EAGAIN ||
                                     returnCode == EBUSY)) {
            this->unlock();
            returnCode = ::pthread_mutex_destroy(&this->mutex_);
            if (returnCode == 0 || ++count == MAX_RETRIES)
                break;
            System::sleep(1);
        }
        
        if (returnCode == 0)
            return;

        System::throwSystemException(returnCode);
    }
    
    void Mutex::lock() {
        Int returnCode = ::pthread_mutex_lock(&this->mutex_);
        
        if (returnCode == 0)
            return;
        
        System::throwSystemException(returnCode);
    }
    
    Bool Mutex::tryLock() {
        Int returnCode = ::pthread_mutex_trylock(&this->mutex_);

        if (returnCode == 0)
            return true;
        else if (returnCode == EBUSY)
            return false;

        System::throwSystemException(returnCode);
    }
    
    void Mutex::unlock() {     
        Int returnCode = ::pthread_mutex_unlock(&this->mutex_);
        
        if (returnCode == 0)
            return;
        
        System::throwSystemException(returnCode);
    }
}
